package ch.ethz.fcl.metrobuzz.render.interchange.temporal;

import java.util.ArrayList;
import java.util.List;

import org.lwjgl.opengl.GL11;

import ch.ethz.fcl.metrobuzz.MBContainer;
import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.interchange.Interchange;
import ch.ethz.fcl.metrobuzz.data.texture.MBTexture;
import ch.ethz.fcl.metrobuzz.render.techniques.circos.CircosMatrix;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Point2D;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Rectangle;
import ch.ethz.fcl.metrobuzz.tools.MBGL;

public class TemporalElementList {
	private MBContainer container;
	private Interchange interchange;
	private String label;

	private List<TemporalElement> elements;
	private Rectangle bound;
	private Rectangle iconRegion;

	// records left and right shift numbers
	private int rightShift;
	private int leftShift;

	public TemporalElementList(MBContainer container, Interchange interchange) {
		this.container = container;
		this.interchange = interchange;
		init();
	}

	public TemporalElementList(String label, MBContainer container,
			Interchange interchange) {
		this.container = container;
		this.interchange = interchange;
		this.label = label;
		init();
	}

	private void init() {
		elements = new ArrayList<TemporalElement>();
		bound = new Rectangle();
		iconRegion = new Rectangle();
	}

	public void setRightShift(int shift) {
		if (MBData.period == MBData.ONE_DAY_TIME)
			this.rightShift = 0;
		else
			this.rightShift = Math.min(
					(MBData.ONE_DAY_TIME - 1 - MBData.startTime)
							/ MBData.period, shift);
	}

	public void setLeftShift(int shift) {
		if (MBData.period == MBData.ONE_DAY_TIME)
			this.leftShift = 0;
		else
			this.leftShift = Math.max(-MBData.startTime / MBData.period - 1,
					shift);
	}

	public int getRightShift() {
		return rightShift;
	}

	public int getLeftShift() {
		return leftShift;
	}

	private void updateBound() {
		Rectangle bound_first = elements.get(0).getBound();
		Rectangle bound_last = elements.get(elements.size() - 1).getBound();
		float minX = Math.min(bound_first.getMinX(), bound_last.getMinX());
		float maxX = Math.max(bound_first.getMaxX(), bound_last.getMaxX());

		float minY = bound_first.getMinY();
		float maxY = bound_first.getMaxY();

		bound = new Rectangle(minX, minY, maxX, maxY);

		float size = bound_first.getWidth() / 8;
		iconRegion = new Rectangle(maxX - size, maxY - size, maxX + size, maxY
				+ size);
	}

	public void addTemporalElement(TemporalElement ele) {
		elements.add(ele);
		updateBound();
	}

	public void update(float radius, float boundSize) {
		elements.clear();

		// recalculate left and right shift to handle timer changes
		setLeftShift(leftShift);
		setRightShift(rightShift);

		for (int i = leftShift; i <= rightShift; i++) {
			float x = interchange.getCircosCentroid().getX() + i * boundSize;
			float y = interchange.getCircosCentroid().getY();

			Point2D c = new Point2D(x, y);
			int start = MBData.startTime + i * MBData.period;
			int end = MBData.startTime + (i + 1) * MBData.period;

			CircosMatrix cd = interchange.getData(start, end);

			TemporalElement te = new TemporalElement(label, cd, c, radius);
			te.setStartTime(start);
			te.setEndTime(end);
			elements.add(te);
		}
		updateBound();
	}

	public List<TemporalElement> getTemporalElements() {
		return elements;
	}

	public void putToRecorded(List<TemporalElementList> lists) {
		if (lists != null)
			lists.add(this);
	}

	public boolean inBound(float x, float y) {
		if (bound == null)
			return false;
		return bound.contains(x, y);
	}

	public boolean inIconBound(float x, float y) {
		if (iconRegion == null)
			return false;
		return iconRegion.contains(x, y);
	}

	public TemporalElement get(int i) {
		return elements.get(i);
	}

	public Interchange getInterchange() {
		return interchange;
	}

	public int size() {
		return elements.size();
	}

	public void render() {
		MBGL.enableBlend();
		for (TemporalElement te : elements)
			te.render(container.getFont());

		MBTexture.renderTexture(
				container.getData().getTexture().getCloseIcon(), iconRegion);

		GL11.glDisable(GL11.GL_BLEND);
	}
}
